﻿using EasyDDD.Domain;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace EasyDDD.Infrastructure.EFCore.Repository
{
    public class EFRepositoryContext<TContext> : DbContext, IUnitOfWork
        where TContext : DbContext
    {
        readonly IMediator mediator;
        //readonly IPublisherTransactionHandler? publisherTransactionFactory;

        public EFRepositoryContext(DbContextOptions<TContext> options, IMediator mediator, IServiceProvider provider)
           : base(options)
        {
            //Database.EnsureCreatedAsync().Wait();
            //if (Database.GetPendingMigrations().Any())
            //{
            //    var p = provider.GetService<ILoggerProvider>();
            //    var f = provider.GetService<ILoggerFactory>();
            //    var logger = p.CreateLogger("数据库迁移");
            //    logger.LogInformation("***数据库迁移开始");
            //    foreach (var migration in Database.GetPendingMigrations())
            //    {
            //        logger.LogInformation(migration);
            //    }
            //    Database.Migrate();
            //    logger.LogInformation("***数据库迁移结束");
            //}

            this.mediator = mediator;
            //this.publisherTransactionFactory = provider.GetService<IPublisherTransactionHandler>();
        }

        //protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
        //{
        //    base.ConfigureConventions(configurationBuilder);
        //    configurationBuilder.ConfigureStronglyTypedIdConventions(this);
        //}

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            //modelBuilder.ConfigureStronglyTypedId();
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.LogTo(Console.WriteLine, LogLevel.Information);
            optionsBuilder.UseLazyLoadingProxies();
            //optionsBuilder.UseChangeTrackingProxies();
            base.OnConfiguring(optionsBuilder);
        }

        public IDbContextTransaction? CurrentTransaction => throw new NotImplementedException();

        public IDbContextTransaction BeginTransaction()
        {
            throw new NotImplementedException();
        }

        public Task CommitAsync(CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public Task RollbackAsync(CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
        {
            var entries = this.ChangeTracker.Entries();
            // foreach (var entry in entries.Where(e => e.State == EntityState.Added))
            // {
            //     // efcore9 GUID主键好像已经默认UUIDv7了
            //     if (entry.Entity.GetType().GetProperty("Id")?.PropertyType == typeof(Guid))
            //     {
            //         entry.Property("Id").CurrentValue = Guid.CreateVersion7();
            //     }
            // }
            foreach (var entry in entries.Where(e => e.State == EntityState.Modified))
            {
                if (entry.Entity.GetType().GetProperty("RowVersion") != null)
                {
                    entry.Property("RowVersion").CurrentValue = Guid.NewGuid();
                }
            }
            return base.SaveChangesAsync(cancellationToken);
        }

        public async Task<int> SaveUnitOfWorkAsync(CancellationToken cancellationToken = default)
        {
            //TODO: 循环事务的试试  可能有问题
            int res = 0;
            try
            {
                res = await this.SaveChangesAsync(cancellationToken);
                await mediator.DispatchDomainEventsAsync(this);
            }
            catch (DbUpdateConcurrencyException ex)
            {
                var bex = new BusinessException(ex);
                bex.Title = "并发错误，数据已被改动";
                foreach (var entry in ex.Entries)
                {
                    //bex.Errors.Add(entry);
                }

                //TODO: 抛出业务错误
                throw bex;
            }
            catch (DbUpdateException)
            {
                throw;
            }
            catch (Exception)
            {
                throw;
            }
            finally
            {
                await mediator.ClearDomainEventsAsync(this);
            }
            return res;
        }
    }
}
